package com.xxg.renrensearch.init;

import com.xxg.renrensearch.dao.*;
import com.xxg.renrensearch.es.RenRenShopEs;
import com.xxg.renrensearch.repository.ProductRepository;
import com.xxg.renrensearch.service.BaiduService;
import com.xxg.renrensearch.service.DbService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 商品数据初始化操作
 *
 * @author xuxiaogang
 * @date 2021-11-24
 */
@Component
public class RenrenShopProductsInit {
    private final Logger logger = LoggerFactory.getLogger(RenrenShopProductsInit.class);
    private final RenrenShopShopInit renrenShopShopInit;
    private final RenRenShopEs renRenShopEs;
    private final RenrenShopGoodsDao renrenShopGoodsDao;
    private final RenrenShopGoodsOptionDao renrenShopGoodsOptionDao;
    private final RenrenShopGoodsCategoryMapDao renrenShopGoodsCategoryMapDao;
    private final ProductRepository productRepository;
    private final static int PAGE_SIZE = 1000;
    private final BaiduService baiduService;
    private final DbService dbService;

    public RenrenShopProductsInit(RenrenShopShopInit renrenShopShopInit, RenRenShopEs renRenShopEs,
                                  RenrenShopGoodsDao renrenShopGoodsDao,
                                  RenrenShopGoodsOptionDao renrenShopGoodsOptionDao,
                                  RenrenShopGoodsCategoryMapDao renrenShopGoodsCategoryMapDao,
                                  ProductRepository productRepository, BaiduService baiduService, DbService dbService) {
        this.renrenShopShopInit = renrenShopShopInit;
        this.renRenShopEs = renRenShopEs;
        this.renrenShopGoodsDao = renrenShopGoodsDao;
        this.renrenShopGoodsOptionDao = renrenShopGoodsOptionDao;
        this.renrenShopGoodsCategoryMapDao = renrenShopGoodsCategoryMapDao;
        this.productRepository = productRepository;
        this.baiduService = baiduService;
        this.dbService = dbService;
        syncData();
    }

    /**
     * 同步商品数据
     */
    public void syncData() {
        logger.info("goods syncData start");
        // 查询索引库中最大的店铺ID和店铺数量
        Integer[] integers = renRenShopEs.getMaxIdCount(Product.class, "spuId");
        int count = integers[0];
        int maxIndexId = integers[1];
        // 查询数据库中最大的店铺ID
        int maxProductId = renrenShopGoodsDao.getMaxId();
        int startId, endId, pages;
        if (count > 0) {
            // 索引库有数据，确定分析范围
            pages = (maxIndexId % PAGE_SIZE == 0) ? (maxIndexId / PAGE_SIZE) : (maxIndexId / PAGE_SIZE + 1);
            // 非最后一页
            for (int i = 0; i < pages - 1; i++) {
                startId = i * PAGE_SIZE + 1;
                endId = (i + 1) * PAGE_SIZE;
                analysisDeleteUpdate(startId, endId);
            }
            // 最后一页
            startId = (pages - 1) * PAGE_SIZE + 1;
            endId = maxIndexId;
            analysisDeleteUpdate(startId, endId);
        }
        if (maxProductId > maxIndexId) {
            // 查询新增数据集
            int newDataCount = maxProductId - maxIndexId;
            pages = (newDataCount % PAGE_SIZE == 0) ? (newDataCount / PAGE_SIZE) : (newDataCount / PAGE_SIZE + 1);
            // 非最后一页
            for (int i = 0; i < pages - 1; i++) {
                startId = i * PAGE_SIZE + maxIndexId + 1;
                endId = (i + 1) * PAGE_SIZE + maxIndexId;
                analysisNew(startId, endId);
            }
            // 最后一页
            startId = (pages - 1) * PAGE_SIZE + maxIndexId + 1;
            endId = maxProductId;
            analysisNew(startId, endId);
        }
        logger.info("goods syncData end");
    }

    /**
     * 分析出删除集合和变更集合
     *
     * @param startId 开始ID
     * @param endId   结束ID
     */
    private void analysisDeleteUpdate(int startId, int endId) {
        logger.info("goods analysisDeleteUpdate range[" + startId + "," + endId + "]");
        // 定义删除集合
        List<String> dList = new LinkedList<>();
        // 定义更新集合
        List<Product> uList = new LinkedList<>();
        List<RenrenShopGoods> shopGoods = renrenShopGoodsDao.selectByIdRange(startId, endId);
        // 查询商品的分类映射
        Map<Integer, List<Integer>> categoryMap = getGoodCategoryMap(startId, endId);
        // 查询商品的规格
        List<RenrenShopGoodsOption> goodsOptions = renrenShopGoodsOptionDao.selectByIdRange(startId, endId);
        Map<Integer, List<RenrenShopGoodsOption>> optionsMap = skuGroupBySpuId(shopGoods.size(), goodsOptions);
        shopGoods.forEach(e -> {
            e.setCategories(categoryMap.get(e.getId()));
            if (e.getHasOption()) {
                // 多规格商品
                if (optionsMap.containsKey(e.getId())) {
                    List<RenrenShopGoodsOption> options = optionsMap.get(e.getId());
                    if (e.getIsDeleted() || !e.getStatus()) {
                        // 删除多个规格的商品
                        List<String> ids = options.stream()
                                .map(option -> e.getId() + "_" + option.getId()).collect(Collectors.toList());
                        dList.addAll(ids);
                    } else {
                        uList.addAll(goodOption2Product(e, options));
                    }
                }
            } else {
                // 单规格商品
                if (e.getIsDeleted() || !e.getStatus()) {
                    // 提取删除的商品
                    dList.add(e.getId() + "_" + e.getId());
                } else {
                    uList.add(good2Product(e));
                }
            }
        });
        // 删除索引
        deleteIndex(dList);
        // 更新索引
        updateIndex(uList);
    }

    /**
     * 查询商品映射
     *
     * @param startId 开始ID
     * @param endId   结束ID
     * @return 结果
     */
    private Map<Integer, List<Integer>> getGoodCategoryMap(int startId, int endId) {
        List<RenrenShopGoodsCategoryMap> categories = renrenShopGoodsCategoryMapDao.selectByGoodIdRange(startId, endId);
        Map<Integer, List<Integer>> listMap = new HashMap<>(categories.size() * 4 / 3 + 1);
        categories.forEach(e -> {
            if (!listMap.containsKey(e.getGoodsId())) {
                listMap.put(e.getGoodsId(), new LinkedList<>());
            }
            listMap.get(e.getGoodsId()).add(e.getCategoryId());
        });
        return listMap;
    }

    /**
     * 多规格商品分组
     *
     * @param goodsOptions 多规格商品信息
     * @return 结果
     */
    private Map<Integer, List<RenrenShopGoodsOption>> skuGroupBySpuId(int size, List<RenrenShopGoodsOption> goodsOptions) {
        // 多规格商品SKU处理
        Map<Integer, List<RenrenShopGoodsOption>> optionsMap = new HashMap<>(size * 4 / 3 + 1);
        goodsOptions.forEach(e -> {
            if (!optionsMap.containsKey(e.getGoodsId())) {
                optionsMap.put(e.getGoodsId(), new LinkedList<>());
            }
            optionsMap.get(e.getGoodsId()).add(e);
        });
        return optionsMap;
    }

    /**
     * 查询出新增集合
     *
     * @param startId 开始ID
     * @param endId   结束ID
     */
    private void analysisNew(int startId, int endId) {
        logger.info("goods analysisNew range[" + startId + "," + endId + "]");
        // 定义新增集合
        List<Product> aList = new ArrayList<>();
        List<RenrenShopGoods> shopGoods = renrenShopGoodsDao.selectByIdRange(startId, endId);
        // 查询商品的分类映射
        Map<Integer, List<Integer>> categoryMap = getGoodCategoryMap(startId, endId);
        // 查询商品规格
        List<RenrenShopGoodsOption> goodsOptions = renrenShopGoodsOptionDao.selectByIdRange(startId, endId);
        Map<Integer, List<RenrenShopGoodsOption>> optionsMap = skuGroupBySpuId(shopGoods.size(), goodsOptions);
        shopGoods.forEach(e -> {
            // 排除删除的商品和下架的商品
            if (!e.getIsDeleted() && e.getStatus()) {
                e.setCategories(categoryMap.get(e.getId()));
                // 提取变更的商品
                if (e.getHasOption()) {
                    // 多规格商品
                    if (optionsMap.containsKey(e.getId())) {
                        List<RenrenShopGoodsOption> options = optionsMap.get(e.getId());
                        aList.addAll(goodOption2Product(e, options));
                    }
                } else {
                    // 单规格商品
                    aList.add(good2Product(e));
                }
            }
        });
        // 添加索引
        addIndex(aList);
    }

    /**
     * 单规格商品转sku
     *
     * @param good SPU
     * @return 结果
     */
    public Product good2Product(RenrenShopGoods good) {
        String id = good.getId() + "_" + good.getId();
        String shopName = "";
        if (renrenShopShopInit.getShopInfoMap().containsKey(good.getShopId())) {
            shopName = renrenShopShopInit.getShopInfoMap().get(good.getShopId()).getName();
        }
        return new Product(id, good.getId(), good.getId(), good.getShopId(), shopName, good.getTitle(),
                good.getTitle(), good.getSubTitle(), good.getShortTitle(), good.getType(), good.getThumb(),
                good.getThumbAll(), good.getVideo(), good.getVideoThumb(), good.getVideoType(), good.getStock(),
                good.getSales(), good.getRealSales(), good.getContent(), good.getIsRecommand(), good.getIsHot(),
                good.getIsNew(), good.getPrice(), good.getMinPrice(), good.getMaxPrice(), good.getCostPrice(),
                good.getCostPrice(), good.getCostPrice(), good.getOriginalPrice(), good.getSales(), null,
                good.getCategories(), good.getStock());
    }

    /**
     * 多规格商品转SKU
     *
     * @param good    SPU
     * @param options 多规格
     * @return 结果
     */
    public List<Product> goodOption2Product(RenrenShopGoods good, List<RenrenShopGoodsOption> options) {
        List<Product> products = new ArrayList<>(options.size());
        Map<Integer, RenrenShopShop> map = renrenShopShopInit.getShopInfoMap();
        BigDecimal minCostPrice = new BigDecimal("0");
        BigDecimal maxCostPrice = new BigDecimal("0");
        for (RenrenShopGoodsOption sku : options) {
            String id = good.getId() + "_" + sku.getId();
            String shopName = "";
            if (map.containsKey(good.getShopId())) {
                shopName = map.get(good.getShopId()).getName();
            }
            String skuName = good.getTitle() + "|" + sku.getTitle();
            Product product = new Product(id, good.getId(), sku.getId(), good.getShopId(), shopName, good.getTitle(),
                    skuName, good.getSubTitle(), good.getShortTitle(), good.getType(), good.getThumb(),
                    good.getThumbAll(), good.getVideo(), good.getVideoThumb(), good.getVideoType(), good.getStock(),
                    good.getSales(), good.getRealSales(), good.getContent(), good.getIsRecommand(), good.getIsHot(),
                    good.getIsNew(), sku.getPrice(), good.getMinPrice(), good.getMaxPrice(), good.getCostPrice(),
                    good.getCostPrice(), sku.getCostPrice(), sku.getOriginalPrice(), sku.getSales(), sku.getThumb(),
                    good.getCategories(), sku.getStock());
            products.add(product);
            if (minCostPrice.compareTo(sku.getCostPrice()) > 0) {
                minCostPrice = sku.getCostPrice();
            }
            if (maxCostPrice.compareTo(sku.getCostPrice()) < 0) {
                maxCostPrice = sku.getCostPrice();
            }
        }
        for (Product p : products) {
            p.setSpuMinCostPrice(minCostPrice);
            p.setSpuMaxCostPrice(maxCostPrice);
        }
        return products;
    }

    /**
     * 新增索引
     *
     * @param goods 新的商品
     */
    private void addIndex(List<Product> goods) {
        if (goods.size() == 0) {
            return;
        }
        productRepository.saveAll(goods);
        logger.info("hour task add products size:" + goods.size());
        baiduService.addOrUpdatePicture(goods);
    }

    /**
     * 更新索引
     *
     * @param goods 变更的商品
     */
    private void updateIndex(List<Product> goods) {
        if (goods.size() == 0) {
            return;
        }
        renRenShopEs.updateGoodsIndex(goods);
        logger.info("hour task update products size:" + goods.size());
        baiduService.addOrUpdatePicture(goods);
    }

    /**
     * 删除索引
     *
     * @param ids 删除的店铺Id列表
     */
    private void deleteIndex(List<String> ids) {
        if (ids.size() == 0) {
            return;
        }
        productRepository.deleteAllById(ids);
        logger.info("hour task delete products size:" + ids.size());
        // 提取spuId
        Set<Integer> set = new HashSet<>(ids.size() * 4 / 3 + 1);
        for (String id : ids) {
            String[] str = id.split("_");
            set.add(Integer.valueOf(str[0]));
        }
        dbService.deleteData(new ArrayList<>(set));
    }
}
